/* 
 * Copyright (c) Sergey B. Berezin (s_berezin@cs.msu.su), 2002, 2003.
 *
 * You may freely distribute or modify this source code retaining the 
 * above copyright notice.
 *
 * This software is provided "as-is" and without guarantee or warrantee 
 * of any kind, expressed or implied :)
 */

using System;
using System.Windows.Forms;

using ManagedGL;

namespace UVS.UI {
	
	public abstract class Layer : IComparable {
		/// <summary>Depth of the layer. Layers with greater depth are rendered first</summary>
		protected int depth;        
		
		/// <summary>LayeredView this layer is attached to or null if this
		/// layer is not attached to any view</summary>
		public LayeredView view; // this field is made public for access in LayeredView
		
		/// <summary>True is this layer is visible</summary>
		protected bool visible = true;

		/// <summary>Invoked when layer is going to be rendered</summary>
		public abstract void OnRender();
	
		/// <summary>Invoked when rendering context is resized</summary>
		public virtual void OnResize() {
			// Handle window resize here
		}

		/// <summary>
		/// Invoked when rendering context is attached. OnContextAttached() and
		/// OnContextDetached() are called in pairs: if OnContextAttached() was called
		/// OnContextDetached() is guaranteed to be called.
		/// </summary>
		public virtual void OnContextAttached() {
			// Make any context dependent initialization here
		}

		/// <summary>Invoked before rendering context is detached</summary>
		public virtual void OnContextDetached() {
			// Release any context dependent resources here
		}

		public int Depth {
			get {
				return depth;
			}
			set {
				depth = value;
				//if(view != null) 
				//	;// TODO: view.Sort();
			}
		}

		public int Width {
			get { 
				return view.Width; 
			}
		}

		public int Height {
			get {
				return view.Height;
			}
		}

		public bool ContextAttached {
			get {
				return (view != null && view.ContextAttached);
			}
		}

		public LayeredView View {
			get {
				return view;
			}
		}

		/// <summary>Changes visibility of layer</summary>
		public bool Visible {
			set {
				if(visible != value) {
					visible = value;
					if(view != null)
						view.UpdateRequested = true;
				}
			}
			get {
				return visible;
			}
		}

		/// <summary>
		/// Compares two layers. Returns -depth.CompareTo(another.depth) or
		/// throws System.ArgumentException if another is not a Layer.  
		/// This allows default Sort() method to arrange layers from back to front 
		/// </summary>
		/// <param name="another">Second layer to compare with</param>
	 
		public int CompareTo(object another) {
			Layer layer2 = another as Layer;
			if(layer2 == null)
				throw new ArgumentException();
			return -depth.CompareTo(layer2.depth);
		}
	};

	///
	/// <summary> UILayer is an extension of Layer that allows interaction with user
	/// throught attached object of System.Windows.Forms.Control class. Also UILayers can 
	/// add their own items to context menu of attached control</summary>
	///

	public abstract class UILayer : Layer {

		/// <summary>
		/// Returns UIView this layer is linked to or null of layer is not
		/// linked to any view or is linked to view that is not derived from UIView.
		/// </summary>
		public UIView UIView {
			get {
				if(view != null)
					return view as UIView;
				else
					return null;
			}
		}

		public bool ControlAttached {
			get {
				UIView uv = UIView;
				if(uv != null)
					return uv.ControlAttached;
				else
					return false;
			}
		}

		public Control Control {
			get {
				UIView uv = UIView;
				if(uv != null)
					return uv.Control;
				else
					return null;
			}
		}

		/// <summary>This method is invoked when this layer (or LayeredView containing it)
		/// is attached to control.</summary>
		/// <remarks>OnControlAttached() and OnControlDetached() methods
		/// are called in pairs in same manner that OnContextAttached() and 
		/// OnContextDetached()</remarks>
		
		public virtual void OnControlAttached() {
			// Initialize all control dependent resources here
		}
		
		/// <summary>This method is invoked before this layer is detached from control.
		/// Here you can release resources and events associated with control</summary>
		/// <remarks>See remarks for <see cref="OnControlAttached"/> method</remarks>

		public virtual void OnControlDetached() {
			// Release all control dependent resources here
		}
		
		public virtual void UpdateContextMenu(ContextMenu menu) {
			// modify context menu here
		}
	}
}